﻿using DryIoc.ImTools;
using Microsoft.EntityFrameworkCore;
using PLCSharp.CoreModel.Common;
using PLCSharp.Views.Authority;
using PLCSharp.Views.Connects;
using PLCSharp.Views.GlobalVariables;
using PLCSharp.Views.Homepage;
using PLCSharp.Views.MotionController;
using PLCSharp.Views.Recipe;
using PLCSharp.Views.Robots;
using PLCSharp.Views.Vision;
using PLCSharp.Views.Vision.Camera;
using PLCSharp.Views.Workflows;

namespace PLCSharp.Models
{
    public class DatasContext : DbContext
    {
        public DatasContext()
        {
            this.EnsureCreatingMissingTables();
            this.Database.EnsureCreated();

        }

        public DbSet<User> Users { get; set; }
        public DbSet<Recipe> Recipes { get; set; }
        public DbSet<Variable> Variables { get; set; }
        public DbSet<Workflow> Workflows { get; set; }
        public DbSet<VisionFunction> VisionFunctions { get; set; }
        public DbSet<ImageData> ImageDatas { get; set; }
        public DbSet<Connect> Connects { get; set; }
        public DbSet<CameraBase> Cameras { get; set; }
        public DbSet<Controller> Controllers { get; set; }
        public DbSet<Axis> Axes { get; set; }
        public DbSet<AxisPoint> AxisPoints { get; set; }
        public DbSet<InterpolationGroup> InterpolationGroups { get; set; }
        public DbSet<DI> DI { get; set; }
        public DbSet<DQ> DQ { get; set; }

        public DbSet<Robot> Robots { get; set; }
        public DbSet<ErrorLog> ErrorLogs { get; set; }
        public DbSet<CustomControl> CustomControls { get; set; }
        public DbSet<CanvasConfig> CanvasConfigs { get; set; }


        public Recipe CurrentRecipe { get; set; }
        protected override void OnConfiguring(DbContextOptionsBuilder options)
            => options.UseSqlite("Data Source=Datas.db");

        private object _dbLock = new object();
        public void Save()
        {
            lock (_dbLock)
            {
                SaveChanges();
            }

        }
    }


    internal static class DbContextExtensions
    {
        internal static void EnsureCreatingMissingTables<TDbContext>(this TDbContext dbContext) where TDbContext : DbContext
        {
            var type = typeof(TDbContext);
            var dbSetType = typeof(DbSet<>);

            var dbPropertyNames = type.GetProperties().Where(p => p.PropertyType.Name == dbSetType.Name)
                .Select(p => p.Name).ToArray();

            foreach (var entityName in dbPropertyNames)
            {
                CheckTableExistsAndCreateIfMissing(dbContext, entityName);
            }
        }

        private static void CheckTableExistsAndCreateIfMissing(DbContext dbContext, string entityName)
        {
            var defaultSchema = dbContext.Model.GetDefaultSchema();
            var tableName = string.IsNullOrWhiteSpace(defaultSchema) ? $"{entityName}" : $"{defaultSchema}.{entityName}";

            try
            {
                var sqlstr = $"SELECT * FROM {tableName} LIMIT 1";
                _ = dbContext.Database.ExecuteSqlRaw(sqlstr); //Throws on missing table
            }
            catch (Exception)
            {
                var scriptStart = $"CREATE TABLE \"{tableName}\"";

                var script = dbContext.Database.GenerateCreateScript();

                var tableScript = script.Split(scriptStart).Last().Split(";");

                var first = $"{scriptStart} {tableScript.First()}";
                if (first is not null)
                    dbContext.Database.ExecuteSqlRaw(first);

            }
        }
    }
}
